package com.andy.contentcenter.configuration;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.util.CollectionUtils;

import javax.naming.NamingEnumeration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <B>系统名称：</B>spring-cloud-alibaba 学习<BR>
 * <B>模块名称：</B>扩展Ribbon<BR>
 * <B>中文类名：</B>支持nacos 同一集群优先调用<BR>
 * <B>概要说明：</B>通过指定nacos的集群名称，自定义实现同一集群优先调用负载均衡算法<BR>
 *
 * @author wsr
 * @since Created in 2019/8/29 14:05
 */
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        //读取配置文件，并初始化NacosSameClusterWeightedRule
        //一般来说都是滞空处理
    }

    @Override
    public Server choose(Object key) {
        try {
            //拿到配置文件中的集群名称
            String clusterName = nacosDiscoveryProperties.getClusterName();

            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //想要请求的微服务的名称
            String name = loadBalancer.getName();

            //拿到服务发现的相关API
            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();

            //1.找到指定服务的所有实例 A
            List<Instance> instances = namingService.selectInstances(name, true);

            //2.过滤出相同集群下的所有实例 B
            List<Instance> sameClusterInstances = instances.stream()
                    .filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
                    .collect(Collectors.toList());

            //3.如果B是空，就用A
            List<Instance> instancesToBeChosen = new ArrayList<>();
            if (CollectionUtils.isEmpty(sameClusterInstances)){
                instancesToBeChosen=instances;
                log.warn("发生跨集群的调用，name = {},clusterName = {},instances = {}",
                        name,
                        clusterName,
                        instances);
            }else{
                instancesToBeChosen=sameClusterInstances;
            }
            //4.基于权重的负载均衡算法，返回1个实例
            Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
            log.info("端口：port = {},实例 instance = {}",instance.getPort(),instance);
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("发生异常了",e);
            return null;
        }
    }
}
/**当想使用其他类中的方法未受保护级别时，可以用继承此类，重写方法*/
class ExtendBalancer extends Balancer{
    public static Instance getHostByRandomWeight2(List<Instance> hosts){
        return getHostByRandomWeight(hosts);
    }
}

